package com.bndg.blackjack.services

import android.content.Context
import android.content.Intent
import android.content.ServiceConnection
import android.os.Binder
import android.os.Handler
import android.os.IBinder
import android.util.Log
import android.widget.Toast
import com.bndg.blackjack.AppUtils
import com.xuhao.didi.core.iocore.interfaces.IPulseSendable
import com.xuhao.didi.core.iocore.interfaces.ISendable
import com.xuhao.didi.core.pojo.OriginalData
import com.xuhao.didi.socket.client.impl.client.action.ActionDispatcher.ActionRunnable
import com.xuhao.didi.socket.client.sdk.OkSocket
import com.xuhao.didi.socket.client.sdk.client.ConnectionInfo
import com.xuhao.didi.socket.client.sdk.client.OkSocketOptions
import com.xuhao.didi.socket.client.sdk.client.OkSocketOptions.ThreadModeToken
import com.xuhao.didi.socket.client.sdk.client.action.ISocketActionListener
import com.xuhao.didi.socket.client.sdk.client.action.SocketActionAdapter
import com.xuhao.didi.socket.client.sdk.client.connection.IConnectionManager
import com.xuhao.didi.socket.client.sdk.client.connection.NoneReconnect
import java.nio.charset.Charset

/**
 * @author r
 * @date 2024/12/9
 * @description 客户端连接服务
 */
class ClientService : BaseService(), ISocketActionListener {
    private var mOkOptions: OkSocketOptions? = null
    private var mManager: IConnectionManager? = null
    private lateinit var mInfo: ConnectionInfo
    private var ipAddress: String? = null
    private var mPort: Int = 8080

    companion object {
        fun bind(
            context: Context,
            ipAddress: String,
            port: Int,
            clientServiceConnection: ServiceConnection,
            bindAutoCreate: Int
        ) {
            val intent = Intent(context, ClientService::class.java)
            intent.putExtra("ipAddress", ipAddress)
            intent.putExtra("port", port)
            context.bindService(intent, clientServiceConnection, bindAutoCreate)
        }
    }

    inner class ClientBinder : Binder() {
        fun getService(): ClientService {
            return this@ClientService
        }
    }

    private val mBinder = ClientBinder()

    override fun onCreate() {
        super.onCreate()
    }

    /**
     * 如果服务被启动（从onStartCommand返回后）后，服务所在进程被杀死，
     * 此时保持服务的启动状态，但是不保持服务之前的Intent。稍后系统会尝试重新创建该服务。
     * 因为该服务目前是启动状态，因此，创建新的服务实例后，一定会调用onStartCommand；
     * 当没有将要传递给服务启动命令时，服务将会被唤醒并附带空的Intent对象，请注意检查该Intent是否为空。
     *
     * @return
     */
    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        Log.d(">>>>", "onStartCommand: ")
        return START_STICKY
    }

    override fun onBind(intent: Intent?): IBinder {
        Log.d(">>>>", "onBind: ")
        initClient(intent)
        return mBinder
    }

    private var adapter = object : SocketActionAdapter() {
        override fun onSocketDisconnection(
            info: ConnectionInfo?,
            action: String?,
            e: Exception?
        ) {
            Log.d(">>>>", "onSocketDisconnection: $action ${e?.message}")
            dataCallback?.onClientConnected()
        }
    }

    private fun initClient(intent: Intent?) {
        ipAddress = intent?.getStringExtra("ipAddress")
        mPort = intent?.getIntExtra("port", 8080) ?: 8080
        ipAddress?.let {
            initManager()
            mManager?.let {
                if (!it.isConnect) {
                    Log.d(">>>>", "initClient: $mManager")
                    it.connect()
                    Log.d(">>>>", "initClient: $ipAddress $mPort")
                }
            }
        }
    }

    private fun initManager() {
        val handler = Handler()
        mInfo = ConnectionInfo(ipAddress, mPort)
        mOkOptions = OkSocketOptions.Builder()
            .setReconnectionManager(NoneReconnect())
            .setConnectTimeoutSecond(10)
            .setCallbackThreadModeToken(object : ThreadModeToken() {
                override fun handleCallbackEvent(runnable: ActionRunnable) {
                    Log.d(">>>>", "handleCallbackEvent: $runnable <>" + Thread.currentThread())
                    handler.post(runnable)
                }
            })
            .build()
        mManager = OkSocket.open(mInfo).option(mOkOptions)
        mManager?.registerReceiver(this@ClientService)
    }

    override fun onDestroy() {
        super.onDestroy()
        mManager?.let {
            AppUtils.log("onDestroy unRegisterReceiver")
            it.disconnect()
            it.unRegisterReceiver(this@ClientService)
        }
    }

    override fun onSocketIOThreadStart(action: String?) {
        Log.d(">>>>", "onSocketIOThreadStart: $action")
    }

    override fun onSocketIOThreadShutdown(action: String?, e: Exception?) {
        Log.d(">>>>", "onSocketIOThreadShutdown: $action ${e?.message}")
    }

    override fun onSocketReadResponse(info: ConnectionInfo?, action: String?, data: OriginalData?) {
        val str = String(data!!.bodyBytes, Charset.forName("utf-8"))
        Log.d(">>>>", "onSocketReadResponse: $str")
        dataCallback?.onReceived(str)
    }

    override fun onSocketWriteResponse(info: ConnectionInfo?, action: String?, data: ISendable?) {
        Log.d(">>>>", "onSocketWriteResponse: ")
    }

    override fun onPulseSend(info: ConnectionInfo?, data: IPulseSendable?) {
        Log.d(">>>>", "onPulseSend: ")
    }

    override fun onSocketDisconnection(info: ConnectionInfo?, action: String?, e: Exception?) {
        Log.d(">>>>", "onSocketDisconnection: $action ${e?.message}")
        dataCallback?.onServerConnected(false)
    }

    override fun onSocketConnectionSuccess(info: ConnectionInfo?, action: String?) {
        Log.d(">>>>", "onSocketConnectionSuccess: $action")
        dataCallback?.onServerConnected(true)
    }

    override fun onSocketConnectionFailed(info: ConnectionInfo?, action: String?, e: Exception?) {
        Log.d(">>>>", "onSocketConnectionFailed: $action ${e?.message}")
    }

    override fun sentMsg(data: String) {
        mManager?.let {
            if (!it.isConnect) {
                Toast.makeText(applicationContext, "Unconnected", Toast.LENGTH_SHORT).show()
            } else {
                val msgDataBean = MsgDataBean(data)
                it.send(msgDataBean)
            }
        }
    }
}